package com.yyfax.pay.console.service.impl;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.yyfax.framework.common.Log;
import com.yyfax.framework.model.Page;
import com.yyfax.pay.common.enums.BusiTypeEnum;
import com.yyfax.pay.common.enums.ExpRecordStateEnum;
import com.yyfax.pay.console.dao.ExceptionRecordDao;
import com.yyfax.pay.console.domain.ExceptionRecordDO;
import com.yyfax.pay.console.service.CommonExceptionService;
import com.yyfax.pay.console.service.ResolveExpRecordService;
import com.yyfax.pay.console.service.ResolverAdaptService;
import com.yyfax.pay.console.vo.DealResultVO;
import com.yyfax.pay.console.vo.OrderInfoVO;
import com.yyfax.pay.vo.consloe.DealExpRsp;
import com.yyfax.pay.vo.consloe.ExceptionRecord;
import com.yyfax.pay.vo.consloe.QueryExpRecordReq;

@Service
public class ResolveExpRecordServiceImpl implements ResolveExpRecordService {

	@Resource
	private ExceptionRecordDao exceptionRecordDao;

	@Resource
	private ResolverAdaptService resolverAdaptService;

	Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * 处理异常记录
	 *
	 * @author wangjwy
	 * @date 2018/7/4 14:28
	 * @since 2.2.3
	 * @param expRecordIds, optMode
	 * @return com.yyfax.pay.vo.consloe.DealExpRsp
	 */
	@Override
	public DealExpRsp resolve(List<Integer> expRecordIds, Integer optMode) {
		final String OP = "ResolveExpRecordServiceImpl.resolve";
		// 根据异常信息主键查询出所有异常记录,过滤掉处理成功的记录
		List<ExceptionRecordDO> exceptionRecordDOS = exceptionRecordDao.queryListByIds(expRecordIds, ExpRecordStateEnum.RESOLVED_SUCCESS.getValue(),
				ExpRecordStateEnum.RESOLVING.getValue());
		logger.info(Log.op(OP).msg("查询到非成功状态记录数").kv("size", exceptionRecordDOS.size()).toString());

		return doResolve(exceptionRecordDOS, optMode);
	}

	/**
	 * 直接关闭异常记录,更新异常记录的状态为处理成功
	 *
	 * @author wangjwy
	 * @date 2018/7/4 14:28
	 * @since 2.2.3
	 * @param expRecordIds, optMode
	 * @return com.yyfax.pay.vo.consloe.DealExpRsp
	 */
	@Override
	public DealExpRsp close(List<Integer> expRecordIds, Integer optMode) {
		final String OP = "ResolveExpRecordServiceImpl.resolve";
		String resultDesc = "已关闭";
		// 直接关闭异常
		int successCount = 0;
		int failCount = 0;
		for (Integer expRecordId : expRecordIds) {
			try {
				exceptionRecordDao.modifyState(expRecordId, ExpRecordStateEnum.RESOLVED_SUCCESS.getValue(), resultDesc, optMode);
				successCount++;
			} catch (Exception e) {
				logger.warn(Log.op(OP).msg("后台关闭异常订单记录异常").kv("expRecordId", expRecordId).toString(), e);
				failCount++;
				continue;
			}
		}
		return new DealExpRsp(successCount, failCount);
	}

	/**
	 * 处理异常记录,根据busiType回调对应的处理器
	 *
	 * @author wangjwy
	 * @date 2018/7/4 14:30
	 * @since 2.2.3
	 * @param exceptionRecordDOS, optMode
	 * @return com.yyfax.pay.vo.consloe.DealExpRsp
	 */
	private DealExpRsp doResolve(List<ExceptionRecordDO> exceptionRecordDOS, Integer optMode) {
		final String OP = "ResolveExpRecordServiceImpl.doResolve";
		ArrayList<Integer> originstates = new ArrayList<>();
		originstates.add(ExpRecordStateEnum.RESOLVED_FAIL.getValue());
		originstates.add(ExpRecordStateEnum.NOT_RESOLV.getValue());
		int successCount = 0;
		int failCount = 0;
		for (ExceptionRecordDO exceptionRecordDO : exceptionRecordDOS) {
			if (changeState(exceptionRecordDO.getId(), ExpRecordStateEnum.RESOLVING.getValue(), originstates, ExpRecordStateEnum.RESOLVING.getDesc(),
					optMode)) {
				continue;
			}
			// 获取对应处理器
			CommonExceptionService adaptiveService = resolverAdaptService.getAdaptiveService(BusiTypeEnum.form(exceptionRecordDO.getBusiType()));
			// 执行处理
			DealResultVO dealResultVO = adaptiveService.dealException(exceptionRecordDO.getBusiId(),
					BusiTypeEnum.form(exceptionRecordDO.getBusiType()), exceptionRecordDO.getExceptionType());
			if (handleResult(optMode, exceptionRecordDO, dealResultVO)) {
				successCount++;
			} else {
				failCount++;
			}
		}
		return new DealExpRsp(successCount, failCount);
	}

	/**
	 * 解析处理返回的结果
	 *
	 * @author wangjwy
	 * @date 2018/7/4 14:31
	 * @since 2.2.3
	 * @param optMode, exceptionRecordDO, dealResultVO
	 * @return boolean
	 */
	private boolean handleResult(Integer optMode, ExceptionRecordDO exceptionRecordDO, DealResultVO dealResultVO) {
		final String OP = "ResolveExpRecordServiceImpl.handleResult";
		ArrayList<Integer> originstates2 = new ArrayList<>();
		originstates2.add(ExpRecordStateEnum.RESOLVING.getValue());
		// 修改异常记录状态为处理成功
		if (ExpRecordStateEnum.RESOLVED_SUCCESS.getValue() == dealResultVO.getState()) {
			changeState(exceptionRecordDO.getId(), ExpRecordStateEnum.RESOLVED_SUCCESS.getValue(), originstates2,
					ExpRecordStateEnum.RESOLVED_SUCCESS.getDesc(), optMode);
			return true;
		} else {
			changeState(exceptionRecordDO.getId(), ExpRecordStateEnum.RESOLVED_FAIL.getValue(), originstates2,
					ExpRecordStateEnum.RESOLVED_FAIL.getDesc(), optMode);
			return false;
		}
	}

	/**
	 * 更新异常记录的状态
	 *
	 * @author wangjwy
	 * @date 2018/7/4 14:32
	 * @since 2.2.3
	 * @param exceptionRecordId, targetState, originstates, desc, optMode
	 * @return boolean
	 */
	private boolean changeState(Integer exceptionRecordId, Integer targetState, ArrayList originstates, String desc, Integer optMode) {
		final String OP = "ResolveExpRecordServiceImpl.changeState";
		// 修改异常记录状态为处理中
		int uCount = exceptionRecordDao.updateState(exceptionRecordId, targetState, originstates, desc, optMode);
		if (1 != uCount) {
			logger.warn(Log.op(OP).msg("修改异常记录状态为命中,不作处理").kv("exceptionRecordId", exceptionRecordId).toString());
			return true;
		}
		return false;
	}

	/**
	 * 根据条件查询异常记录
	 *
	 * @author wangjwy
	 * @date 2018/7/4 14:33
	 * @since 2.2.3
	 * @param req
	 * @return com.yyfax.framework.model.Page<com.yyfax.pay.vo.consloe.ExceptionRecord>
	 */
	@Override
	public Page<ExceptionRecord> listExceptionRecords(QueryExpRecordReq req) {
		String OP = "ResolveExpRecordServiceImpl.listExceptionRecords";
		// 根据条件查询分页查询异常记录
		int count = exceptionRecordDao.selectCountEffective(req.getBusiId(), req.getBeginTime(), req.getEndTime(), req.getState());
		int pageSize = req.getPageSize();
		int start = (req.getPageNo() - 1) * pageSize;
		List<ExceptionRecordDO> dataList = exceptionRecordDao.listExceptionRecords(req.getBusiId(), req.getBeginTime(), req.getEndTime(),
				req.getState(), start, pageSize);
		ArrayList<ExceptionRecord> exceptionRecords = new ArrayList<>();
		OrderInfoVO orderInfoVO = null;
		for (ExceptionRecordDO exceptionRecordDO : dataList) {
			// 获取对应处理器
			try {
				CommonExceptionService adaptiveService = resolverAdaptService.getAdaptiveService(BusiTypeEnum.form(exceptionRecordDO.getBusiType()));
				orderInfoVO = adaptiveService.queryOrderInfo(exceptionRecordDO.getBusiId());
				ExceptionRecord exceptionRecord = buildExceptionRecord(exceptionRecordDO, orderInfoVO);
				exceptionRecords.add(exceptionRecord);
			} catch (Exception e) {
				logger.warn(Log.op(OP).msg("封装异常记录异常").kv("exceptionRecordDO", exceptionRecordDO).kv("orderInfoVO", orderInfoVO).toString(), e);
				continue;
			}
		}
		Page<ExceptionRecord> page = new Page<>(req.getPageNo(), req.getPageSize(), count, exceptionRecords);
		return page;
	}

	/**
	 * 构建响应
	 *
	 * @author wangjwy
	 * @date 2018/7/3 9:25
	 * @since 2.2.3
	 * @param exceptionRecordDO, orderInfoVO
	 * @return com.yyfax.pay.vo.consloe.ExceptionRecord
	 * @throws Exception
	 */
	private ExceptionRecord buildExceptionRecord(ExceptionRecordDO exceptionRecordDO, OrderInfoVO orderInfoVO) {
		ExceptionRecord exceptionRecord = new ExceptionRecord();
		exceptionRecord.setAmount(orderInfoVO.getAmount());
		exceptionRecord.setBusiId(exceptionRecordDO.getBusiId());
		exceptionRecord.setBusiName(exceptionRecordDO.getBusiName());
		exceptionRecord.setExpMessage(exceptionRecordDO.getExpMessage());
		exceptionRecord.setId(exceptionRecordDO.getId());
		exceptionRecord.setOrderTime(exceptionRecordDO.getOrderTime());
		exceptionRecord.setState(exceptionRecordDO.getState());
		exceptionRecord.setResolveTime(exceptionRecordDO.getUpdateTime());
		exceptionRecord.setUserId(orderInfoVO.getUserId());
		return exceptionRecord;
	}
}
